﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;
using SlimMath;

namespace MyTestProject {

    public class TestTransformable {
        [Fact]
        public void TestConstructor () {
            var node = new Group ();

            var vec0001 = new float[] { 0, 0, 0, 1 };
            var vec111  = new float[] { 1, 1, 1 };
            var matI    = new float[] {1,0,0,0,
                                       0,1,0,0,
                                       0,0,1,0,
                                       0,0,0,1};
            var vec000 = new float[] { 0, 0, 0 };

            Assert.Equal (0.0f, node.Orientation[0]);
            Assert.Equal (vec0001, node.OrientationQuat);
            Assert.Equal (vec111, node.Scaling);
            Assert.Equal (vec000, node.Translation);
            Assert.Equal (matI, node.Transform.Matrix);
            Assert.Equal (matI, node.CompositeTransform.Matrix);
        }



        [Fact]
        public void TestSetOrientation () {
            var node = new Group ();
            node.SetOrientation (45, 1, 1, 1);

            // 回転軸は正規化されて返ってくる
            var expected = new float[] { 45, 0.5773503f, 0.5773503f, 0.5773503f };

            Assert.Equal (expected, node.Orientation, new FloatComparere (0.0001f));
        }

        [Fact]
        public void TestSetOrientationLookAtZ () {
            var node = new Group ();
            node.SetOrientationLookAt (-1, 0, -1,  // target
                                       0, 2, 0);   // up

            var expected = new float[] { 45, 0, 1, 0 };

            Assert.Equal (expected, node.Orientation, new FloatComparere (0.0001f));
        }

        [Fact]
        public void TestSetOrientationLookAtX () {
            var node = new Group ();
            node.SetOrientationLookAt (-1, 0, 0,  // target
                                       -1, 1, 0); // up

            var expected = new float[] { 90, 0, 1, 0 };

            Assert.Equal (expected, node.Orientation, new FloatComparere (0.0001f));
        }

        [Fact]
        public void TestSetOrientationLookAtY () {
            var node = new Group ();
            node.SetOrientationLookAt (0, -1, 0,  // target
                                       0, 1, 1);  // up

            var expected = new float[] { 180, 0, 0.7071068f, 0.7071068f };

            Assert.Equal (expected, node.Orientation, new FloatComparere (0.0001f));
        }

        [Fact]
        public void TestSetOrientationQuat () {
            var node = new Group ();
            node.SetOrientationQuat (1, 1, 1, 1);

            var expected = new float[] { 1, 1, 1, 1 }; // Quaternion

            Assert.Equal (expected, node.OrientationQuat);
        }

        [Fact]
        public void TestSetScale () {
            var node = new Group ();
            node.SetScale (1, 2, 3); ;

            var expected = new float[] { 1, 2, 3 };

            Assert.Equal (expected, node.Scaling);
        }

        [Fact]
        public void TestScale () {
            var node = new Group ();
            node.SetScale (2, 2, 2);
            node.Scale (1, 2, 3);

            var expected = new float[] { 2, 4, 6 };

            Assert.Equal (expected, node.Scaling);
        }


        [Fact]
        public void TestSetTranslation () {
            var node = new Group ();
            node.SetTranslation (1, 2, 3);

            var expected = new float[] { 1, 2, 3 };

            Assert.Equal (expected, node.Translation);
        }

        [Fact]
        public void TestTranslate () {
            var node = new Group ();
            node.SetTranslation (1, 1, 1);
            node.Translate (1, 2, 3);

            var expected = new float[] { 2, 3, 4 };

            Assert.Equal (expected, node.Translation);
        }

        [Fact]
        public void TestSetTransform () {
            var node   = new Group ();

            var tra = new Transform ();
            tra.Matrix = new float[]{1,2,3,4,
                                     5,6,7,8,
                                     9,10,11,12,
                                     0, 0, 0, 1};
            node.SetTransform (tra);

            var expected = new float[]{1,2,3,4,
                                       5,6,7,8,
                                       9,10,11,12,
                                       0, 0, 0, 1};

            Assert.Equal (expected, node.Transform.Matrix);
        }

        [Fact]
        public void TestGetCompositeTransform () {
            var node = new Group ();
            var matrix = new float[] {1,0,0,1,
                                      0,2,0,2,
                                      0,0,3,3,
                                      0,0,0,1};
            node.SetScale (1, 2, 3);
            node.SetOrientation (90, 1, 0, 0);
            node.SetTranslation (2, 2, 2);
            node.SetTransform (new Transform (matrix));

            var expected = new float[] { 1, 0, 0, 3,
                                         0, 0,-9,-7,
                                         0, 4, 0, 6,
                                         0, 0, 0, 1 };

            Assert.Equal (expected, node.CompositeTransform.Matrix, new FloatComparere (0.00001f));
        }

        [Fact]
        public void TestPostRotate () {
            var nod = new Group ();
            nod.PostRotate (90, 1, 0, 0);
            nod.PostRotate (90, 0, 0, 1);

            var expected = new float[] { 120, 0.5773503f, 0.5773503f, 0.5773503f };

            Assert.Equal (expected, nod.Orientation, new FloatComparere (0.00001f));
        }

        [Fact]
        public void TestPostRotateQuat () {
            var nod = new Group ();
            var q1 = Quaternion.RotationAxis (new Vector3 (1, 0, 0), 90 * (float)Math.PI / 180.0f);
            var q2 = Quaternion.RotationAxis (new Vector3 (0, 0, 1), 90 * (float)Math.PI / 180.0f);
            nod.PostRotateQuat (q1[0], q1[1], q1[2], q1[3]);
            nod.PostRotateQuat (q2[0], q2[1], q2[2], q2[3]);

            var expected = new float[] { 120, 0.5773503f, 0.5773503f, 0.5773503f };

            Assert.Equal (expected, nod.Orientation, new FloatComparere (0.00001f));
        }


        [Fact]
        public void TestPreRotate () {
            var nod = new Group ();
            nod.PreRotate (90, 1, 0, 0);
            nod.PreRotate (90, 0, 0, 1);

            var expected = new float[] { 120, 0.5773503f, -0.5773503f, 0.5773503f };

            Assert.Equal (expected, nod.Orientation, new FloatComparere (0.00001f));
        }




        [Fact]
        public void TestPreRotateQuat () {
            var nod = new Group ();
            var q1  = Quaternion.RotationAxis (new Vector3 (1, 0, 0), 90 * (float)Math.PI / 180.0f);
            var q2  = Quaternion.RotationAxis (new Vector3 (0, 0, 1), 90 * (float)Math.PI / 180.0f);
            nod.PreRotateQuat (q1[0], q1[1], q1[2], q1[3]);
            nod.PreRotateQuat (q2[0], q2[1], q2[2], q2[3]);

            var expected = new float[] { 120, 0.5773503f, -0.5773503f, 0.5773503f };

            Assert.Equal (expected, nod.Orientation, new FloatComparere (0.00001f));
        }

        [Fact]
        public void TestDuplicate () {
            var nod = new Group ();
            var tra = new Transform (new float[]{1,2,3,4,
                                                 5,6,7,8,
                                                 9,10,11,12,
                                                 0, 0, 0, 1});
            nod.SetTranslation (1, 2, 3);
            nod.SetOrientationQuat (1, 1, 1, 1);
            nod.SetScale (1, 2, 3); ;
            nod.SetTransform (tra);

            var dup = (Transformable)nod.Duplicate ();

            Assert.Equal (nod.Orientation, dup.Orientation);
            Assert.Equal (nod.OrientationQuat, dup.OrientationQuat);
            Assert.Equal (nod.Scaling, dup.Scaling);
            Assert.Equal (nod.Translation, dup.Translation);
            Assert.Equal (nod.Transform.Matrix, dup.Transform.Matrix);
            Assert.Equal (nod.CompositeTransform.Matrix, dup.CompositeTransform.Matrix);
        }


    }
}
